import {
  Group,
  RepeatWrapping,
  LineBasicMaterial,
  Vector3,
  SpriteMaterial,
  Sprite,
  Color,
  MeshStandardMaterial,
  MeshLambertMaterial,
  DoubleSide,
  MeshBasicMaterial,
  AdditiveBlending,
} from "three";
import { ExtrudeMap } from "./map/extrudeMap";
import { getBoundBox, emptyObject, PathLine, Debug } from "@/mini3d";
import { geoMercator } from "d3-geo";
import { gsap } from "gsap";
import emitter from "@/utils/emitter";
import { Time } from "../../mini3d/utils";
import testData from "@/assets/test-child";
import testData2 from "@/assets/test-child-2";
let clickNum = 0;
export class ChildMap {
  constructor(parent, options) {
    this.parent = parent;
    this.instance = new Group();
    this.instance.rotateX(-Math.PI / 2);
    this.instance.position.set(0, 0.2, 0);
    let defaultOptions = {
      adcode: 10000,
      center: [0, 0],
      centroid: [0, 0],
      childrenNum: 0,
      parentBoxSize: [1, 1], // 上级地图的尺寸
      mapData: {},
      geoProjectionCenter: [0, 0],
      geoProjectionScale: 120,
      geoProjectionTranslate: [0, 0],
    };
    this.options = Object.assign({}, defaultOptions, options);
    this.time = options.time;
    // 是否点击了
    this.clicked = false;
    // 缩放值
    this.scale = 1;
    // 地图的box大小
    this.boundBox = {};
    // 地图的区域数据
    this.areaData = [];
    // 区域标签
    this.allAreaLabel = [];
    // 区域标签组
    this.areaLabelGroup = new Group();
    // 区域点组
    this.areaPointGroup = new Group();
    // 信息标签组
    this.allInfoLabel = [];
    this.infoLabelGroup = new Group();
    this.instance.add(
      this.areaLabelGroup,
      this.areaPointGroup,
      this.infoLabelGroup
    );
    // 事件元素
    this.eventElement = [];
    this.pointEventElement = [];
    this.init();
  }
  init() {
    debugger;
    this.createModel();
    this.createStorke();

    this.addLabel();
    this.addPointLabel(testData);
    if (this.options.childrenNum) {
      this.addEvent();
    }
    this.addPointEvent();
  }
  createModel() {
    let { map } = this.createMap();
    this.setScale(map);
    map.setParent(this.instance);
  }
  // 创建省份
  createMap() {
    // 广东地图
    let mapJsonData = this.options.mapData || this.options.storkeMapData;
    let topNormal = this.parent.assets.instance.getResource("topNormal");
    topNormal.wrapS = topNormal.wrapT = RepeatWrapping;

    // 地图线
    this.mapLineMaterial = new LineBasicMaterial({
      color: 0xffffff,
      opacity: 1,
      transparent: true,
      fog: false,
    });
    let [topMaterial, sideMaterial] = this.parent.createProvinceMaterial();
    let clonedSideMaterial = cloneWithShader(sideMaterial);
    clonedSideMaterial.opacity = 1;
    let map = new ExtrudeMap(this.parent, {
      center: this.options.center,
      position: new Vector3(0, 0, 0.06),
      data: mapJsonData,
      depth: this.parent.depth,
      topFaceMaterial: topMaterial,
      sideMaterial: clonedSideMaterial,
      lineMaterial: this.mapLineMaterial,
      renderOrder: 9,
    });
    this.areaData = map.coordinates;

    let { boxSize, box3 } = getBoundBox(map.mapGroup);
    map.mapGroup.children.map((group, index) => {
      group.children.map((mesh) => {
        if (mesh.type === "Mesh") {
          mesh.userData.type = "map";
          this.eventElement.push(mesh);
          this.parent.calcUv2(
            mesh.geometry,
            boxSize.x,
            boxSize.y,
            box3.min.x,
            box3.min.y
          );
        }
      });
    });

    return {
      map,
    };
  }

  addEvent() {
    let objectsHover = [];

    const reset = (mesh) => {
      gsap.to(mesh.scale, {
        duration: 0.3,
        z: 1,
        onComplete: () => {
          mesh.traverse((obj) => {
            if (obj.isMesh) {
              obj.material[0].emissive.setHex(
                mesh.userData.materialEmissiveHex
              );
              obj.material[0].emissiveIntensity = 1;
              obj.renderOrder = 9;
            }
          });
        },
      });

      this.setLabelMove(mesh.userData.adcode, "down");
      this.setPointMove(mesh.userData.adcode, "down");
    };
    const move = (mesh) => {
      gsap.to(mesh.scale, {
        duration: 0.3,
        z: 1.5,
      });

      this.setLabelMove(mesh.userData.adcode);
      this.setPointMove(mesh.userData.adcode);

      mesh.traverse((obj) => {
        if (obj.isMesh) {
          obj.material[0].emissive.setHex(0x337ecc);
          obj.material[0].emissiveIntensity = 2.5;
          obj.renderOrder = 21;
        }
      });
    };

    // 循环添加事件
    this.eventElement.map((mesh) => {
      this.parent.interactionManager.add(mesh);
      mesh.addEventListener("mousedown", (event) => {
        if (this.clicked) return false;
        this.clicked = true;
        let userData = event.target.parent.userData;
        emitter.$emit("loadChildMap", userData);
        this.parent.history.push(userData);
        this.parent.loadChildMap(userData);
      });
      mesh.addEventListener("mouseup", (ev) => {
        this.clicked = false;
      });
      mesh.addEventListener("mouseover", (event) => {
        if (!objectsHover.includes(event.target.parent)) {
          objectsHover.push(event.target.parent);
        }
        document.body.style.cursor = "pointer";
        // 放大对应地块的label
        const adcode = event.target.parent.userData.adcode;
        this.allAreaLabel.forEach((label) => {
          if (label.userData.adcode === adcode) {
            // 记录原始scale，便于后续还原
            if (!label.userData.originalScale) {
              label.userData.originalScale = {
                x: label.scale.x,
                y: label.scale.y,
                z: label.scale.z,
              };
            }
            gsap.to(label.scale, {
              x: label.userData.originalScale.x * 1.5,
              y: label.userData.originalScale.y * 1.5,
              z: label.userData.originalScale.z * 1.5,
              duration: 0.3,
            });
          }
        });
        move(event.target.parent);
      });
      mesh.addEventListener("mouseout", (event) => {
        objectsHover = objectsHover.filter(
          (n) => n.userData.name !== event.target.parent.userData.name
        );
        if (objectsHover.length > 0) {
          const mesh = objectsHover[objectsHover.length - 1];
        }
        reset(event.target.parent);
        const adcode = event.target.parent.userData.adcode;
        this.allAreaLabel.forEach((label) => {
          if (label.userData.adcode === adcode) {
            // 还原到原始scale
            const ori = label.userData.originalScale || {
              x: this.scale,
              y: this.scale,
              z: this.scale,
            };
            gsap.to(label.scale, { 
              x: ori.x,
              y: ori.y,
              z: ori.z,
              duration: 0.3,
            });
          }
        });
        document.body.style.cursor = "default";
      });
    });
  }
  // 添加标点事件
  addPointEvent() {
    let objectsHover = [];

    this.pointEventElement.map((mesh) => {
      this.parent.interactionManager.add(mesh);
      mesh.addEventListener("mousedown", (event) => {
        if (this.clicked) return false;
        this.clicked = true;
        let userData = event.target.userData;
        this.allInfoLabel.map((label, index) => {
          label.hide();
          if (userData.index === index) {
            label.show();
          }
        });
      });
      mesh.addEventListener("mouseup", (ev) => {
        this.clicked = false;
      });
      mesh.addEventListener("mouseover", (event) => {
        if (!objectsHover.includes(event.target.parent)) {
          objectsHover.push(event.target.parent);
        }

        document.body.style.cursor = "pointer";
        let sprite = event.target;
        sprite.material = this.pointHoverMaterial.clone();
      });
      mesh.addEventListener("mouseout", (event) => {
        objectsHover = objectsHover.filter(
          (n) => n.userData.name !== event.target.parent.userData.name
        );
        if (objectsHover.length > 0) {
          const mesh = objectsHover[objectsHover.length - 1];
        }

        document.body.style.cursor = "default";
        let sprite = event.target;
        sprite.material = this.pointDefaultMaterial.clone();
      });
    });
  }
  // 设置标签移动
  setLabelMove(adcode, type = "up") {
    [...this.allAreaLabel].map((label) => {
      if (label.userData.adcode === adcode) {
        gsap.to(label.position, {
          duration: 0.3,
          z:
            type === "up"
              ? label.userData.position[2] + 3 / this.scale
              : label.userData.position[2],
        });
      }
    });
  }
  // 设置点移动
  setPointMove(adcode, type = "up") {
    this.areaPointGroup.children.map((point) => {
      if (point.userData.adcode === adcode) {
        gsap.to(point.position, {
          duration: 0.3,
          z:
            type === "up"
              ? point.userData.position[2] + 3 / this.scale
              : point.userData.position[2],
        });
      }
    });
  }
  addLabel() {
    // 贴图
    // const texture = this.parent.assets.instance.getResource("point");

    // const material = new SpriteMaterial({
    //   map: texture,
    //   color: 0xffffff,
    //   transparent: true,
    //   depthTest: false,
    //   fog: false,
    // });
    // this.pointDefaultMaterial = material;
    // this.pointHoverMaterial = material.clone();
    // this.pointHoverMaterial.color = new Color(0xffffff);
    // const sprite = new Sprite(material);
    // sprite.renderOrder = 23;
    this.areaData.map((item, index) => {
      let [x, y] = this.geoProjection(item.centroid);
      // 名称
      let nameLabel = this.labelNameStyle(item, index, new Vector3(x, -y, 0));
      this.allAreaLabel.push(nameLabel);
      // 信息
      let infoLabel = this.infoLabel(item, index, new Vector3(x, -y, 0));
      this.allInfoLabel.push(infoLabel);

      // //点
      // let areaPoint = sprite.clone();
      // sprite.material = material.clone();
      // areaPoint.position.set(x, -y, 0);
      // areaPoint.userData.adcode = item.adcode;

      // areaPoint.userData.type = "point";
      // areaPoint.userData.name = item.name;
      // areaPoint.userData.position = [x, -y, 0];
      // areaPoint.userData.index = index;
      // this.areaPointGroup.add(areaPoint);
    });
    this.setNameScale();
    this.setInfoScale();
    this.setPointScale();
  }
  infoLabel(data, index, position) {
    let label3d = this.parent.label3d;
    let label = label3d.create("", "info-point", true);

    label.init(
      ` <div class="info-point-wrap">
      <div class="info-point-wrap-inner">
        <div class="info-point-line">
          <div class="line"></div>
          <div class="line"></div>
          <div class="line"></div>
        </div>
        <div class="info-point-content">
          <div class="content-item"><span class="label">名称</span><span class="value">${data.name}</span></div>
          <div class="content-item"><span class="label">PM2.5</span><span class="value">100ug/m²</span></div>
          <div class="content-item"><span class="label">等级</span><span class="value">良好</span></div>
        </div>
      </div>
    </div>
  `,
      position
    );
    label3d.setLabelStyle(label, 0.06 / this.scale, "x");
    label.setParent(this.infoLabelGroup);
    label.hide();
    return label;
  }
  // 城市标签
  labelNameStyle(data, index, position) {
    let label3d = this.parent.label3d;
    let label = label3d.create("", "area-name-label", true);
    label.init(
      `<div class="area-name-label-wrap">${data.name}</div>`,
      position
    );
    label3d.setLabelStyle(label, 0.08 / this.scale, "x");
    label.setParent(this.areaLabelGroup);
    label.userData.adcode = data.adcode;
    label.userData.position = [position.x, position.y, position.z];
    return label;
  }

  calculateScale(parentBoxSize, boxSize) {
    let xScale = parentBoxSize[0] / boxSize[0];
    let yScale = parentBoxSize[1] / boxSize[1];
    let scale = Math.min(xScale, yScale);

    return scale;
  }

  setScale(map) {
    let { parentBoxSize } = this.options;
    let boundBox = getBoundBox(map.mapGroup);

    let scale = this.calculateScale(parentBoxSize, [
      boundBox.boxSize.x,
      boundBox.boxSize.y,
    ]);
    // 子地图缩放到主地图大小
    map.mapGroup.scale.set(scale, scale, 1);
    let boundBox1 = getBoundBox(map.mapGroup);
    // 放大后，中心坐标有偏移，偏移了多少，就反向移动多少
    map.mapGroup.position.x = -boundBox1.center.x;
    map.mapGroup.position.y = -boundBox1.center.y;
    this.scale = scale;
    this.boundBox = boundBox1;
  }

  setNameScale() {
    this.areaLabelGroup.scale.set(this.scale, this.scale, this.scale);

    this.areaLabelGroup.position.x = -this.boundBox.center.x;
    this.areaLabelGroup.position.y = -this.boundBox.center.y;
    this.allAreaLabel.map((label) => {
      let z = (this.parent.depth + 0.4) / this.scale;
      label.position.z = z;

      label.position.y -= 1.5 / this.scale;
      label.userData.position = [
        label.position.x,
        label.position.y,
        label.position.z,
      ];
    });
  }

  setPointScale() {
    this.areaPointGroup.scale.set(this.scale, this.scale, this.scale);

    this.areaPointGroup.position.x = -this.boundBox.center.x;
    this.areaPointGroup.position.y = -this.boundBox.center.y;
    this.areaPointGroup.children.map((point) => {
      let z = (this.parent.depth + 1.4) / this.scale;
      point.position.z = z;
      point.userData.position[2] = z;

      point.scale.set(5 / this.scale, 5 / this.scale, 5 / this.scale);

      point.userData.position = [
        point.position.x,
        point.position.y,
        point.position.z,
      ];

      this.pointEventElement.push(point);
    });
  }
  setInfoScale() {
    this.infoLabelGroup.scale.set(this.scale, this.scale, this.scale);
    this.infoLabelGroup.position.x = -this.boundBox.center.x;
    this.infoLabelGroup.position.y = -this.boundBox.center.y;
    this.infoLabelGroup.children.map((point) => {
      let z = (this.parent.depth + 10) / this.scale;
      point.position.z = z;

      point.scale.set(0.06 / this.scale, 0.06 / this.scale, 0.06 / this.scale);
    });
  }
  geoProjection = (args) => {
    let { geoProjectionScale, geoProjectionTranslate, center } = this.options;
    return geoMercator()
      .center(center)
      .scale(geoProjectionScale)
      .translate(geoProjectionTranslate)(args);
  };

  setParent(parent) {
    parent.add(this.instance);
  }

  destroy() {
    if (this.pathLine) {
      this.pathLine.destroy();
      this.pathLine = null;
    }
    [...this.allAreaLabel, ...this.allInfoLabel].map((label) => {
      label.remove();
    });
    this.removeElement(".area-name-label");
    this.removeElement(".info-point");
    [...this.eventElement, ...this.pointEventElement].map((mesh) => {
      this.parent.interactionManager.remove(mesh);
    });

    emptyObject(this.instance);
  }
  removeElement(elementClassName) {
    var elements = document.querySelectorAll(elementClassName);
    for (let i = 0; i < elements.length; i++) {
      const element = elements[i];
      const parent = element.parentNode;
      parent.removeChild(element);
    }
  }

  createStorke() {
    if (this.pathLine) {
      this.pathLine.destroy();
      this.pathLine = null;
    }
    // 贴图
    const texture = this.parent.assets.instance.getResource("pathLine2");
    texture.wrapS = texture.wrapT = RepeatWrapping;
    texture.repeat.set(1, 1);
    // 路径
    // let mapJsonData = this.assets.instance.getResource("chinaStorke");
    let mapJsonData = this.options.storkeMapData;
    mapJsonData = JSON.parse(mapJsonData);
    console.log("mapJsonData", mapJsonData);
    console.log("texture", texture);
    // 数据
    // 格式 [{geometry: {type: '', coordinates: [[[x,y]]] }}]
    let data = mapJsonData.features.map((path) => {
      return {
        geometry: path.geometry,
      };
    });
    this.pathLine = new PathLine(this, {
      data: data,
      texture: texture,
      renderOrder: 21,
      speed: 0.002,
      radius: 0.2,
      segments: 256 * 10,
      radialSegments: 4,
      material: new MeshBasicMaterial({
        color: 0x2bc4dc,
        map: texture,
        alphaMap: texture,
        fog: false,
        transparent: true,
        opacity: 1,
        blending: AdditiveBlending,
      }),
    });
    // 设置父级
    this.pathLine.setParent(this.instance);
    // 位置]
    this.pathLine.instance.position.z = this.parent.depth + 0.38;
    this.pathLine.instance.scale.set(this.scale, this.scale, 1);
    this.pathLine.instance.position.x = -this.boundBox.center.x;
    this.pathLine.instance.position.y = -this.boundBox.center.y;
  }
  addPointLabel(data) {
    // 贴图
    clickNum++;
    if (clickNum >= 2) {
      data = testData2;
    }

    const texture = this.parent.assets.instance.getResource("point");
    const material = new SpriteMaterial({
      map: texture,
      color: 0xffffff,
      transparent: true,
      depthTest: false,
      fog: false,
    });
    this.pointDefaultMaterial = material;
    this.pointHoverMaterial = material.clone();
    this.pointHoverMaterial.color = new Color(0xff0000);
    const sprite = new Sprite(material);
    sprite.renderOrder = 23;
    this.allPointLabel = [];
    this.allInfoLabel = [];
    this.pointEventElement = [];
    this.areaPointGroup.clear();
    this.infoLabelGroup.clear();
    // this.areaLabelGroup.clear();
    let _this = this;
    data.map((item, index) => {
      let [x, y] = this.geoProjection(item.centroid);
      // 应用缩放和偏移
      let px = x;
      let py = -y;
      let infoLabel = _this.infoLabel(item, index, new Vector3(px, py, 20));
      this.allInfoLabel.push(infoLabel);

      // 根据 value 字段设置不同颜色
      let color = 0xffffff; // 默认白色
      if (item.value >= 7) {
        color = 0xf56c6c; // 红色
      } else if (item.value >= 5) {
        color = 0xe6a23c; // 黄色
      } else {
        color = 0xb3e19d; // 绿色
      }

      // 为每个点单独创建 material
      let pointMaterial = new SpriteMaterial({
        map: texture,
        color: color,
        transparent: true,
        depthTest: false,
        fog: false,
      });

      let areaPoint = new Sprite(pointMaterial);
      areaPoint.position.set(px, py, 1);
      areaPoint.scale.set(0, 0, 0); // 初始缩放为0
      areaPoint.material.opacity = 1; //
      areaPoint.userData.adcode = item.adcode;
      areaPoint.userData.type = "point";
      areaPoint.userData.name = item.name;
      areaPoint.userData.position = [px, py, 0];
      areaPoint.userData.index = index;
      this.areaPointGroup.add(areaPoint);
      this.pointEventElement.push(areaPoint);

      // 设置渲染顺序
      areaPoint.renderOrder = 199;
      areaPoint.userData.originalMaterial = pointMaterial; // 保存原始材质
      areaPoint.userData.originalColor = pointMaterial.color.clone(); // 保存原始颜色
    });
    this.setPointScale();
    this.addPointEvent();
    this.setInfoScale();
  }

  addPointEvent() {
    let objectsHover = [];
    this.pointEventElement.map((mesh, idx) => {
      this.parent.interactionManager.add(mesh);
      mesh.addEventListener("mouseup", (ev) => {
        this.clicked = false;
      });
      mesh.addEventListener("mouseover", (event) => {
        if (!objectsHover.includes(event.target)) {
          let userData = event.target.userData;
          this.allInfoLabel.map((label, index) => {
            label.hide();
            if (userData.index === index) {
              label.show();
              return;
            }
          });
          objectsHover.push(event.target);
        }
        document.body.style.cursor = "pointer";
        let sprite = event.target;
        sprite.renderOrder = 99999;
        sprite.material.color.set(0xff0000); // 高亮色
      });
      mesh.addEventListener("mouseout", (event) => {
        this.allInfoLabel.map((label, index) => {
          label.hide();
        });
        objectsHover = objectsHover.filter(
          (n) => n.userData.name !== event.target.userData.name
        );
        if (objectsHover.length > 0) {
          const mesh = objectsHover[objectsHover.length - 1];
        }
        document.body.style.cursor = "default";
        let sprite = event.target;
        // 还原为原始颜色
        sprite.material.color.copy(sprite.userData.originalColor);

        this.allAreaLabel.forEach((label) => {
          if (label.userData.adcode === adcode) {
            // 记录原始scale，便于后续还原
            if (!label.userData.originalScale) {
              label.userData.originalScale = {
                x: label.scale.x,
                y: label.scale.y,
                z: label.scale.z,
              };
            }
            gsap.to(label.scale, {
              x: label.userData.originalScale.x * 1.5,
              y: label.userData.originalScale.y * 1.5,
              z: label.userData.originalScale.z * 1.5,
              duration: 0.3,
            });
          }
        });
      });
    });
  }
}

// clone后继承shader的辅助函数
function cloneWithShader(material) {
  const newMat = material.clone();
  if (material.onBeforeCompile) {
    newMat.onBeforeCompile = material.onBeforeCompile;
    newMat.needsUpdate = true;
  }
  return newMat;
}
